package com.baizhi.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

@Component//让Spring管理起来这个类
@Aspect//这个是一个额外增强类
public class LogAspect {

    //以后只要看到logAnntation这个注解，这个方法就是一个切入点方法
  @Pointcut("@annotation(com.baizhi.aspect.LogAnnotation)")
    //@Pointcut("execution(* com.baizhi.service..*.*(..))")
    public void pointcut(){}
    //定义切入点 execution表达式 还可以使用注解
    private Logger logger= LoggerFactory.getLogger(LogAspect.class);


    //aop定义额外功能 1创建原始对象 2定义增强类 3配置增强类 4 定义切点 5 编制组装

    @After("pointcut()")//后置增强，放在目标之后 aop放在pointcut这个切入点上置为后置增强
    //参数joinPoint链接点，可以获取目标对象和目标方法,目标方法的实参
    public void aop(JoinPoint jp){
        //1日志中的name
        UserDetails userDetails = (UserDetails)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String username = userDetails.getUsername();

        //2日志中的用户登录的iP
        //类型转换
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes httpRequestAttributes = (ServletRequestAttributes)requestAttributes;
        //获取request
        HttpServletRequest request = httpRequestAttributes.getRequest();
        //通过request获取用户登录使用的机器的ip
        String ip = request.getRemoteHost();

        //那个用户操作了那个方法，传递了那些参数
        MethodSignature signature =(MethodSignature) jp.getSignature();
        Method method = signature.getMethod();//目标方法
        String name = method.getName();//得到目标方法的方法名。
        Object[] args = jp.getArgs();

        //4从方法上获取注解
        LogAnnotation annotation = method.getDeclaredAnnotation(LogAnnotation.class);
        System.out.println("annotation = " + annotation);
//从注解中获取操作类型和内容
        String type = annotation.type();
        String content = annotation.content();
        logger.info("用户{}登录的ip{}运行了{}方法,传递的参数{},用户的操作类型是{},用户的操作内容是{}",username,ip,name,args,type,content);
    }
}
